package com.framework.mybatis.config;

import cn.hutool.core.util.ClassUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.toolkit.PluginUtils;
import com.baomidou.mybatisplus.extension.plugins.inner.InnerInterceptor;
import com.framework.common.auto.ThreadLocalUtils;
import com.framework.common.auto.UserInfo;
import com.framework.mybatis.anno.DataPermission;
import com.framework.mybatis.anno.DataPermissionIgnore;
import com.framework.mybatis.enums.PermissionTypeEnum;
import lombok.extern.slf4j.Slf4j;
import net.sf.jsqlparser.JSQLParserException;
import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.expression.Parenthesis;
import net.sf.jsqlparser.expression.operators.conditional.AndExpression;
import net.sf.jsqlparser.parser.CCJSqlParserUtil;
import net.sf.jsqlparser.schema.Column;
import net.sf.jsqlparser.statement.select.PlainSelect;
import net.sf.jsqlparser.statement.select.Select;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlCommandType;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.sql.SQLException;
import java.util.List;
import java.util.Objects;

/**
 * @author lihanbo
 * @version 1.0
 * @date 2022/3/2 13:56
 */
@Component
@Slf4j
public class MyDataScopeInterceptor implements InnerInterceptor {

    @Override
    public void beforeQuery(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
        PluginUtils.MPBoundSql mpBs = PluginUtils.mpBoundSql(boundSql);
        String originalSql = boundSql.getSql();
        Object parameterObject = boundSql.getParameterObject();
        SqlCommandType sqlCommandType = ms.getSqlCommandType();

        Select select = null;
        try {
            select = (Select) CCJSqlParserUtil.parse(originalSql);
        } catch (JSQLParserException e) {
            e.printStackTrace();
        }
        PlainSelect plainSelect = (PlainSelect) select.getSelectBody();
        String whereSql = sqlWhere(ms.getId());
        if (StrUtil.isNotEmpty(whereSql)) {
            Expression where = plainSelect.getWhere();
            if (null == where) {
                plainSelect.setWhere(new Column(whereSql));
            } else {
                plainSelect.setWhere(new AndExpression(new Parenthesis(where), new Column("(" + whereSql + ")")));
            }
        }

        mpBs.sql(select.toString());
    }


    public String sqlWhere(String id) {
        UserInfo userInfo = ThreadLocalUtils.getUserInfo();
        if (Objects.isNull(userInfo)) {
            return "";
        }
        if (userInfo.getIsSuper()) {
            return "";
        }
        if (userInfo.getIsAdmin()) {
            // 通过类全路径获取Class对象
            Class<?> classType = ClassUtil.loadClass(id.substring(0, id.lastIndexOf(".")));
            // 获取当前所拦截的方法名称
            String mName = id.substring(id.lastIndexOf(".") + 1);
            Method[] methods = classType.getMethods();
            for (Method method : methods) {
                if (method.getName().equals(mName)) {
                    DataPermissionIgnore methodAnnotation = method.getAnnotation(DataPermissionIgnore.class);
                    DataPermission annotation = classType.getAnnotation(DataPermission.class);
                    if (Objects.isNull(annotation)) {
                        annotation = method.getAnnotation(DataPermission.class);
                    }
                    if (Objects.isNull(methodAnnotation) && Objects.nonNull(annotation)) {
                        String column = annotation.column();
                        //扩展不同类型的权限
                        PermissionTypeEnum type = annotation.type();
                        if (type.equals(PermissionTypeEnum.user)) {
                            //当前用户
                            return getUserSql(column);
                        } else if (type.equals(PermissionTypeEnum.dept)) {
                            //部门权限
                            String roleDeptSql = getRoleDeptSql(column);
                            if (StrUtil.isEmpty(roleDeptSql)) {
                                return " 1 = 2 ";
                            } else {
                                return roleDeptSql;
                            }
                        }
                    }
                }
            }
        }
        return "";
    }

    public String getUserSql(String column) {
        StringBuffer applySql = new StringBuffer();
        applySql.append(column + " = '" + ThreadLocalUtils.getUserId() + "'");
        return applySql.toString();
    }

    public String getRoleDeptSql(String column) {
//        SysDeptService sysDeptService = SpringContextUtil.getBean(SysDeptService.class);
        List<String> deptList = ThreadLocalUtils.getTokenUserInfo().getDeptList();
        StringBuffer applySql = new StringBuffer();
        String sql = "";
        if (deptList != null) {
            long count = deptList.stream().filter(x -> x.equals("1")).count();
            if (count == 0) {
                deptList.forEach(x -> {
                    applySql.append(column + " like '%," + x + ",%'");
                });
                sql = applySql.toString().replaceAll("'" + column, "' or " + column);
            }
        }
        return sql;
    }
}
